#ifndef _ODN_SCENE_SCENE_H
#define _ODN_SCENE_SCENE_H

//Engine headers
#include "odn_scene_SceneElement.h"
#include "odn_scene_SceneObject.h"
#include "odn_file_Reader.h"

//Standard library headers
#include <vector>

#define DEFAULT_SCENE_WIDTH 100
#define DEFAULT_SCENE_HEIGHT 100

//TODO: See if can make this a variable instead
#define DEFAULT_SECTOR_WIDTH 100
#define DEFAULT_SECTOR_HEIGHT 100

namespace ouden
{
	namespace scene
	{
		
		class ODN_Scene : public ouden::file::ODN_LoadableObject 
		{
			
		public:
			
			//Constructor 
			ODN_Scene(Vector3D Size = Vector3D(DEFAULT_SCENE_WIDTH, DEFAULT_SCENE_HEIGHT)) : size(Size), visible(false), active(false)		
			{
				
				//Initialise the sector settings 
				setSectorSize(Vector3D(DEFAULT_SECTOR_WIDTH, DEFAULT_SECTOR_HEIGHT)); 
				
			}
			
			//Destructor 
			~ODN_Scene();
			
			//Updates all scene elements 
			bool Update();
			
			//Draws all scene elements 
			bool Draw();
			
			//Allocates all scene objects into sectors for quick lookup
			bool Sectorise();
			
			//Makes all interactive objects interact with each other 
			bool Interact()
			{
				
				//Loop through objects 
				for (int i=0;i<sceneobjects.size();i++) {
					
					//Get nearby objects from sectors 
					std::vector<ODN_SceneObject*> NearbyObjects = getNearbyObjects(sceneobjects[i]->pos);
					
					//Loop through the nearby objects 
					for (int j=0;j<NearbyObjects.size();j++) {
						
						//Interact the object with all its nearby objects
						if (NearbyObjects[j] && NearbyObjects[j] != sceneobjects[i]) {
							sceneobjects[i]->onInteractWith(NearbyObjects[j]);
						}
						
					}
					
				}
				
			}
		
			//Adds a new element to the scene 
			ODN_SceneElement* addElement(ODN_SceneElement* e);
		
			//Adds a new object to the scene 
			ODN_SceneObject* addObject(ODN_SceneObject* b);
		
			//Remove an element from the scene 
			void killElement(ODN_SceneElement* e);
			
			//Variable access functions
			bool isVisible()				{ return visible; }
			bool isActive()					{ return active; }
			void Show()						{ visible = true; }
			void Hide()						{ visible = false; }
			void Run()						{ active = true; }
			void Pause()					{ active = false; }
			
			void setSize(Vector3D Size)					{ size=Size; }
			void setSectorSize(Vector3D SectorSize); 
			
			//Overloaded data loading functions for persistence 
			virtual void readDataHeader()		{}
			virtual void processDataSection(sSectionHeader SectionHeader)		{}
		
		private:
			
			//Is the scene visible?
			bool visible;
			//Is the scene actively updating? 
			bool active;
			
			//Dimensions of the scene 
			Vector3D size;
			
			//Sector system components
			//------------------------
			
			//Size and number of sectors 
			Vector3D sectorsize;
			Vector3D sectorcount;
			
			//Sector structure containing array of objects 
			struct sSector { std::vector<ODN_SceneObject*> objects; };
			
			//2 dimensional array of sectors 
			std::vector<std::vector<sSector > > sectors;
			
			//Function that returns an array of all the objects in nearby sectors from a point 
			std::vector<ODN_SceneObject*> getNearbyObjects(Vector3D Pos);
			
			//------------------------
			
			//Array of all scene elements
			std::vector<ODN_SceneElement*> sceneelements;
			
			//Array of all scene objects, which as opposed to simple elements, have a physical presence in the scene 
			std::vector<ODN_SceneObject*> sceneobjects;
			
		};
		
	} //namespace scene 
} //namespace ouden 

#endif //_ODN_SCENE_SCENE_H
